/*
 * $Id: ether.c,v 1.7 2005-12-09 05:22:09 bacon Exp $
 */

#include <xp/net/ether.h>
#include <xp/bas/ctype.h>
#include <xp/bas/stdlib.h>
#include <xp/bas/string.h>

int xp_ether_aton (const xp_char_t* str, xp_byte_t hw[XP_ETHER_LEN])
{
	xp_size_t idx = 0;
	const xp_char_t* p = str;

	/*while (xp_isspace(*p)) p++;*/

	while (*p != XP_CHAR('\0')) {
		if (*p >= XP_CHAR('0') && *p <= XP_CHAR('9')) {
			hw[idx] = hw[idx] * 16 + (*p - XP_CHAR('0'));
		}
		else if (*p >= XP_CHAR('A') && *p <= XP_CHAR('F')) {
			hw[idx] = hw[idx] * 16 + (*p - XP_CHAR('A') + 10);
		}
		else if (*p >= XP_CHAR('a') && *p <= XP_CHAR('f')) {
			hw[idx] = hw[idx] * 16 + (*p - XP_CHAR('a') + 10);
		}
		else return -1;
		p++;

		if (*p >= XP_CHAR('0') && *p <= XP_CHAR('9')) {
			hw[idx] = hw[idx] * 16 + (*p - XP_CHAR('0'));
		}
		else if (*p >= XP_CHAR('A') && *p <= XP_CHAR('F')) {
			hw[idx] = hw[idx] * 16 + (*p - XP_CHAR('A') + 10);
		}
		else if (*p >= XP_CHAR('a') && *p <= XP_CHAR('f')) {
			hw[idx] = hw[idx] * 16 + (*p - XP_CHAR('a') + 10);
		}
		else return -1;
		p++;

		if (idx < 5) {
			if (*p != XP_CHAR(':')) return -1;
		}
		else {
			if (*p != XP_CHAR('\0')) return -1;
			return 0;
		}

		p++;
		idx++;
	}

	if (idx != XP_ETHER_LEN) return -1;
	return 0;
}

int xp_ether_xaton (
	const xp_char_t* str, xp_size_t len, xp_byte_t hw[XP_ETHER_LEN])
{
	xp_size_t idx = 0;
	const xp_char_t* p = str, * end = str + len;

	/*while (p < end && xp_isspace(*p)) p++;*/

	while (p < end) {
		if (*p >= XP_CHAR('0') && *p <= XP_CHAR('9')) {
			hw[idx] = hw[idx] * 16 + (*p - XP_CHAR('0'));
		}
		else if (*p >= XP_CHAR('A') && *p <= XP_CHAR('F')) {
			hw[idx] = hw[idx] * 16 + (*p - XP_CHAR('A') + 10);
		}
		else if (*p >= XP_CHAR('a') && *p <= XP_CHAR('f')) {
			hw[idx] = hw[idx] * 16 + (*p - XP_CHAR('a') + 10);
		}
		else return -1;
		p++;

		if (p >= end) return -1;
		if (*p >= XP_CHAR('0') && *p <= XP_CHAR('9')) {
			hw[idx] = hw[idx] * 16 + (*p - XP_CHAR('0'));
		}
		else if (*p >= XP_CHAR('A') && *p <= XP_CHAR('F')) {
			hw[idx] = hw[idx] * 16 + (*p - XP_CHAR('A') + 10);
		}
		else if (*p >= XP_CHAR('a') && *p <= XP_CHAR('f')) {
			hw[idx] = hw[idx] * 16 + (*p - XP_CHAR('a') + 10);
		}
		else return -1;
		p++;

		if (idx < 5) {
			if (p >= end) return -1;
			if (*p != XP_CHAR(':')) return -1;
		}
		else {
			if (p < end) return -1;
			return 0;
		}

		p++;
		idx++;
	}

	if (idx != XP_ETHER_LEN) return -1;
	return 0;
}

xp_size_t xp_ether_ntoa (
	const xp_byte_t hw[XP_ETHER_LEN], 
	xp_char_t* buf, xp_size_t size)
{
	xp_size_t i;
	xp_char_t tmp[XP_ETHER_LEN][3];
	
	if (size <= 0) return 0;

	for (i = 0; i < XP_ETHER_LEN; i++) {
		xp_bytetostr_upper (hw[i], 
			tmp[i], xp_countof(tmp[i]), 16, XP_CHAR('0'));
	}

	return xp_strxapp (buf, size, 
		tmp[0], XP_TEXT(":"), tmp[1], XP_TEXT(":"),
		tmp[2], XP_TEXT(":"), tmp[3], XP_TEXT(":"),
		tmp[4], XP_TEXT(":"), tmp[5], XP_NULL);
}
